﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;

namespace U01_boke
{
    /// <summary>
    /// 类型转换
    /// </summary>
    public class TypeConversion
    {
        #region 数据源类型为SqlDataReader
        /// <summary>
        /// SqlDataReader转换成可迭代类型
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="reader">SqlDataReader</param>
        public static IEnumerable<T> SqlDataReaderToTypeList<T>(SqlDataReader reader)
        {
            try
            {
                List<T> list = new List<T>();
                Type type = typeof(T);
                PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                if (properties.Length == 0)
                    throw new Exception("no find available element！");
                while (reader.Read())
                {
                    T obj = DataReaderMap<T>(properties, reader);
                    list.Add(obj);
                }
                return list;
            }
            finally
            {
                reader?.Close();
            }
        }

        /// <summary>
        /// SqlDataReader转换成指定类型
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="reader">SqlDataReader</param>
        public static T SqlDataReaderToType<T>(SqlDataReader reader)
        {
            try
            {
                Type type = typeof(T);
                PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                if (properties.Length == 0)
                    throw new Exception("no find available element！");
                T obj = default(T);
                while (reader.Read())
                {
                    obj = DataReaderMap<T>(properties, reader);
                }
                return obj;
            }
            finally
            {
                reader?.Close();
            }
        }

        private static T DataReaderMap<T>(PropertyInfo[] properties, SqlDataReader reader)
        {
            T obj = Activator.CreateInstance<T>();
            int length = reader.FieldCount;
            foreach (var item in properties)
            {
                if (!item.CanWrite) continue;
                for (int i = 0; i < length; i++)
                {
                    try
                    {
                        if (item.Name == reader.GetName(i))
                        {
                            if (reader[i] is DBNull) break;
                            item.SetValue(obj, reader[i]);
                            break;
                        }
                    }
                    catch (ArgumentException)
                    {
                        break;
                    }
                }
            }
            return obj;
        }

        #endregion

        #region 数据源为DataTable
        /// <summary>
        /// DataTabl转换成指定可迭代类型，延迟转换
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="dt">DataTable</param>
        /// <returns></returns>
        public static IEnumerable<T> SqlDataTableToTypeList<T>(DataTable dt)
        {
            Type type = typeof(T);
            PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            var column = dt.Columns;
            foreach (DataRow row in dt.Rows)
            {
                T t = Activator.CreateInstance<T>();
                foreach (var prop in properties)
                {
                    if (column.Contains(prop.Name))
                    {
                        try
                        {
                            prop.SetValue(t, row[prop.Name]);
                        }
                        catch (ArgumentException)
                        {
                        }
                    }
                }
                if (t == null) continue;
                yield return t;
            }
        }
        #endregion

        #region 数据有为DataRow

        public static T SqlDataRowToType<T>(DataRow row)
        {
            Type type = typeof(T);
            PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            T t = Activator.CreateInstance<T>();
            foreach (var prop in properties)
            {
                if (row.Table.Columns.Contains(prop.Name))
                {
                    try
                    {
                        prop.SetValue(t, row[prop.Name]);
                    }
                    catch (ArgumentException)
                    {
                    }
                }
            }
            return t;
        }

        #endregion
    }
}